#pragma once

#include <sys/ipc.h>
#include <sys/shm.h>
#include <iostream>
#include <string>
#include <unistd.h>

#define GDE_FAULT_ID -1
#define G_SIZE 4096
#define PATH_NAME "."
#define PROJ_ID 12

#define ERR_EXIT(m)\
do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }\
while (0)

#define CREATER "creater"
#define USER "user"


class Shm
{
private:
    int _shmId;
    size_t _shmSize;
    void * _start_mem;
    std::string _user_type;
    key_t _key;

    void createShmHelper(int flg)
    {
        _shmId = shmget(_key,_shmSize,flg);
        if(_shmId < 0)
        {
            ERR_EXIT("shmget");
        }
        std::cout<<"shmId:"<<_shmId<<std::endl;
    }

    void createShm()
    {
        createShmHelper(IPC_CREAT|IPC_EXCL|0666);
    }

    void getShm()
    {
        createShmHelper(IPC_CREAT);
    }

    void attach()
    {
        _start_mem = shmat(_shmId,nullptr,0);
        if(((intptr_t)_start_mem) < 0)
        {
            ERR_EXIT("shmat");
        }
        std::cout<<"共享内存挂载成功"<<std::endl;
    }

    void detach()
    {
        int n = shmdt(_start_mem);
        if(n == 0)
        {
            std::cout<<"共享内存去挂载成功"<<std::endl;
        }else{
            std::cout<<"共享内存去挂载失败"<<std::endl;

        }
    }

    void destroy()
    {
        if(_shmId == GDE_FAULT_ID)
            return;
        detach();
        int n = shmctl(_shmId,IPC_RMID,nullptr);
        if(n >= 0)
        {
            std::cout<<"共享内存【"+std::to_string(_shmId)+"】删除成功"<<std::endl;

        }
        else
        {
            ERR_EXIT("shmctl");
        }
    }


public:
    Shm(const std::string& pathname,const int projid,const std::string& userType)
    :_shmId(GDE_FAULT_ID),
    _shmSize(G_SIZE),
    _start_mem(0),
    _user_type(userType)
    {
        _key = ftok(pathname.c_str(),projid);
        if(_key < 0)
        {
            ERR_EXIT("ftok");
        }
        std::cout<<"key:"<<_key<<std::endl;
        if(_user_type == CREATER)
            createShm();
        else if(_user_type == USER)
            getShm();
        else
        {}
        attach();
    }
    Shm(const std::string& pathname,const int projid,const std::string& userType,size_t size)
    :_shmId(GDE_FAULT_ID),
    _shmSize(size),
    _start_mem(0),
    _user_type(userType)
    {
        _key = ftok(pathname.c_str(),projid);
        if(_key < 0)
        {
            ERR_EXIT("ftok");
        }
        std::cout<<"key:"<<_key<<std::endl;
        if(_user_type == CREATER)
            createShm();
        else if(_user_type == USER)
            getShm();
        else
        {}
        attach();
    }

    int size()
    {
        return _shmSize;
    }

    void* vrittalAddr()
    {
        std::cout<<"start_mem:"<<_start_mem<<std::endl;
        return _start_mem;
    }

    ~Shm()
    {
        if(_user_type == CREATER)
            destroy();
    }
};
